#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <strings.h>
#include "cJSON.h"

#define N 2048
#define PORT 6060

void *new_sock(void *arg)
{
    printf("will recv new connect\n");
    int sockfd, clientfd,fd;
    char buf[N] = {};
    int addrlen = sizeof(struct sockaddr);
    struct sockaddr_in addr, cliadder;
    int nbytes = 0;

    //创建第二次tcp接收Qt发送的点表
    // 1创建一个套接字--socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        exit(-1);
    }
    // 2定义套接字地址--sockaddr_in
    bzero(&addr, addrlen);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT - 1);
    // 3绑定套接字--bind
    if (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        exit(-1);
    }
    // 4启动监听--listen
    if (listen(sockfd, 5) < 0)
    {
        perror("listen err");
        exit(-1);
    }
    // 5接收连接--accept
    clientfd = accept(sockfd, (struct sockaddr *)&addr, &addrlen);
    if (clientfd < 0)
    {
        perror("accept err");
        exit(-1);
    }

    printf("recv new client\n");

    // 6收发数据--recv/send

    bzero(buf, N);
    nbytes = recv(clientfd, buf, sizeof(buf), 0);
    if (nbytes > 0)
    {

        printf("recv %s-%d data = %s\n", inet_ntoa(cliadder.sin_addr),
               ntohs(cliadder.sin_port), buf);

        //将读取到的点表写入到指定路径下的文件中
        fd = open("/mnt/config/node.json", O_RDWR | O_CREAT | O_TRUNC, 0777);
        write(fd, buf, nbytes);

        // 将停止的讯号序列化后发送给Qt
        cJSON *root_3 = cJSON_CreateObject();
        cJSON_AddItemToObject(root_3, "type", cJSON_CreateNumber(2));
        cJSON *data_3 = cJSON_CreateObject();
        cJSON_AddItemToObject(data_3, "flag", cJSON_CreateString("stop"));
        cJSON_AddItemToObject(root_3, "data", data_3);
        char *p = cJSON_Print(root_3);
        bzero(buf, sizeof(buf));
        memcpy(buf, p, sizeof(buf));
        send(clientfd, buf, strlen(buf), 0);

        free(p);
        cJSON_Delete(root_3);
    }
    else
    {
        printf("peer exit\n");
        exit(-1);
    }
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    //创建udp
    int devfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (devfd < 0)
    {
        perror("devfd err\n");
        return -1;
    }

    int optval = 1;//设置udp广播属性
    setsockopt(devfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // 设置地址重用

    // 填充网络信息
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8080); //udp端口号为8080
    saddr.sin_addr.s_addr = INADDR_ANY;

    int len = sizeof(caddr);

    // 绑定
    if (bind(devfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err\n");
        return -1;
    }

    char buf[N] = {};
    // 接受Qt消息
    while (1)
    {
        bzero(buf, N);
        recvfrom(devfd, buf, N, 0, (struct sockaddr *)&caddr, &len);
        printf("ip:%s port:%d says:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);

        if (strcmp(buf, "group") != 0) //匹配Qt发送的“group”
        {
            printf("udp con err\n");
            continue;
        }

        //给udp发送“yes”表示收到Qt发送的包
        sendto(devfd, "yes", 3, 0, (struct sockaddr *)&caddr, len); 
        printf("udp conned\n");
        break;
    }

    close(devfd);
    // 创建第一次tcp连接
    // 创建套接字
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("tcpfd socket err\n");
        return -1;
    }
    struct sockaddr_in addr__;

    addr__.sin_family = AF_INET;
    addr__.sin_port = htons(PORT); //设置第一次tcp连接的端口号为6060
    addr__.sin_addr.s_addr = INADDR_ANY;
    // 绑定
    if (bind(tcpfd, (struct sockaddr *)&addr__, sizeof(addr__)) < 0)
    {
        perror("tcp bind err\n");
        return -1;
    }

    //监听
    if (listen(tcpfd, 6) < 0)
    {
        perror("tcp listen err\n");
        return -1;
    }

    int LEN__ = sizeof(addr__);

    //接受第一次tcp连接的客户端套接字
    int acceptfd = accept(tcpfd, (struct sockaddr *)&addr__, &LEN__);
    if (acceptfd < 0)
    {
        printf("accept err\n");
        return -1;
    }
    printf("ip:%s tcp,login\n", inet_ntoa(caddr.sin_addr));

    int ret;
    while (1)
    {
        bzero(buf, N);
        ret = recv(acceptfd, buf, sizeof(buf), 0); //接受Qt端发送的点表
        printf("%s\n", buf);

        cJSON *root = cJSON_Parse(buf);
        cJSON *item = cJSON_GetObjectItem(root, "type");
        printf("%s:%d\n", item->string, item->valueint);
        //反序列化点表，根据type的值进行判断

        int type = item->valueint;
        if (type == 1) // 给Qt客户端返回配置信息
        {
            cJSON *root_1 = cJSON_CreateObject();
            cJSON_AddItemToObject(root_1, "type", cJSON_CreateNumber(1));
            cJSON_AddItemToObject(root_1, "result", cJSON_CreateNumber(0));
            cJSON_AddItemToObject(root_1, "up_config", cJSON_CreateString("true"));

            char *p = cJSON_Print(root_1);
            bzero(buf, N);
            memcpy(buf, p, sizeof(buf));
            printf("%s\n", buf); //打印给Qt的配置信息
            send(acceptfd, buf, strlen(buf), 0); //发送给Qt
            free(p);
            cJSON_Delete(root_1);
        }
        else if (type == 2)
        {
            //根据Qt发送的“flag”确定开始接收或停止接收
            cJSON *data = cJSON_GetObjectItem(root, "data");
            cJSON *flag = cJSON_GetObjectItem(data, "flag");
            if (strcmp(flag->valuestring, "start") == 0) //开始接收
            {
                bzero(buf, sizeof(buf));
                cJSON *root_2 = cJSON_CreateObject();
                cJSON_AddItemToObject(root_2, "type", cJSON_CreateNumber(2));
                cJSON *data = cJSON_CreateObject();
                cJSON_AddItemToObject(root_2, "data", data);
                cJSON_AddItemToObject(data, "flag", cJSON_CreateString("start"));
                char *p = cJSON_Print(root_2);
                bzero(buf, N);
                memcpy(buf, p, sizeof(buf));
                // printf("%s\n", buf);

                //将返回的“type”和“data”下的“start”发送给Qt
                //表示自己可以开始进行接收
                send(acceptfd, buf, strlen(buf), 0);
                free(p);
                cJSON_Delete(root_2);

                pthread_t tid_recv; //建立线程处理Qt发送过来的点表
                if (pthread_create(&tid_recv, NULL, new_sock, NULL) != 0)
                {
                    perror("tid_recv create err\n");
                    return -1;
                }
            }
            else
            {
                printf("not start\n");
            }
        }
        else if (type == 3)
        {
            // 心跳检测
            cJSON *root = cJSON_CreateObject();
            cJSON *item = cJSON_CreateNumber(3);
            cJSON_AddItemToObject(root, "type", item);
            item = cJSON_CreateNumber(0);
            cJSON_AddItemToObject(root, "result", item);

            char *p = cJSON_Print(root);
            memcpy(buf, p, sizeof(buf));
            printf("%s\n", buf);
            send(tcpfd, buf, sizeof(buf), 0);
            free(p);
            cJSON_Delete(root);
        }
    }

    close(acceptfd);
    close(tcpfd);
    return 0;
}
